using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
using System.Reflection;

using ca.metaobjects.csogateway;
using ca.metaobjects.csogateway.Reflection;

namespace ca.metaobjects.csogateway.Controls
{
	/// <summary>
	/// Renders a script tag containing a javascript statement that creates a javascript value equivalent to the specified cso-compatible object.
	/// </summary>
	[DefaultProperty("VariableNameOnClientSide")]
	[ToolboxData("<{0}:ObjectGateway runat=server></{0}:ObjectGateway>")]
	public class ObjectGateway : WebControl
    {
		private string objectCreationString = null;

		private string variableNameOnClientSide;
		/// <summary>
		/// Gets or sets the name of the variable to which the newly created javascript value will be assign to.
		/// </summary>
		public string VariableNameOnClientSide
		{
			get
			{
				return variableNameOnClientSide;
			}
			set
			{
				variableNameOnClientSide = value;
			}
		}

		private object sourceObject;
		/// <summary>
		/// Gets or sets the cso-compatible object from which the javascript value will be created.
		/// 
		/// <remarks>
		/// It is not necessary to re-assign the server-side object on every post-back. The generated string of javascript code is store in the control
		/// state on the first request to the page. The assignment of the object can be put in an <code>if(!IsPostBack){...}</code> block of code in the Page_Load
		/// method.
		/// 
		/// If the server-side object changes and the changes need to be reflected on the client side, re-assign the
		/// object to this property. The control state will invalidated and the server-side object will be sent to the Object Gateway again. 
		/// </remarks>
		/// </summary>
		public object SourceObject
        {
            get
            {
                return sourceObject;
            }
            set
            {
				sourceObject = value;
				invalidateCachedObjectCreationString();
            }
        }

		private bool trapException;
		/// <summary>
		/// For debug purposes. Gets or sets a value defining if exceptions should be caught and the exception message assigned to the
		/// variable instead of letting the exception reach the surface.
		/// </summary>
		/// <value>true to trap the exceptions and assign the exception message to the variable name. false to let the exception go and reach the surface.
		/// false to let the exception reach the surface.</value>
		[DefaultValue(false)]
		public bool TrapException
		{
			get
			{
				return trapException;
			}
			set
			{
				trapException = value;
			}
		}
		
		/// <summary>
		/// Event handler for the init event.
		/// </summary>
		/// <param name="e">The event arguments</param>
		protected override void OnInit(EventArgs e)
        {
            Page.RegisterRequiresControlState(this);
            base.OnInit(e);
        }

		/// <summary>
		/// Restores control-state information from a previous page request that was saved by the SaveControlState method.
		/// </summary>
		/// <param name="savedState">An Object that represents the control state to be restored. </param>
		protected override void LoadControlState(object savedState)
        {
			objectCreationString = (string)savedState;
        }

		/// <summary>
		/// Saves any server control state changes that have occurred since the time the page was posted back to the server.
		/// </summary>
		/// <returns>Returns the server control's current state or null if there is no state. </returns>
		protected override object SaveControlState()
		{
			return objectCreationString;
		}

        private void invalidateCachedObjectCreationString()
		{
			objectCreationString = null;
		}

		/// <summary>
		/// Prepare the rendering of the control.
		/// </summary>
		/// <param name="e">Event arguments</param>
		protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            if (!Page.IsPostBack || objectCreationString == null)
            {
                StringBuilder builder = new StringBuilder();

				if (!trapException)
				{
					ToClientSideMainConverter.RenderCsoCompatibleObject(SourceObject, builder);
					objectCreationString = builder.ToString();
				}
				else
				{
					try
					{
						ToClientSideMainConverter.RenderCsoCompatibleObject(SourceObject, builder);
						objectCreationString = builder.ToString();
					}
					catch (Exception ex)
					{
						objectCreationString = (String.Format("'{0}'", ex.Message));
					}
				}
            }
        }
        
		/// <summary>
		/// Render a javascript statement instantiating a javascript value equivalent to the object given to the property SourceObject and
		/// assigning it to a variable named as the value of property VariableNameOnClientSide.
		/// </summary>
		/// <param name="writer">The writer to write the reponse to.</param>
		protected override void Render(HtmlTextWriter writer)
        {
			writer.Write("<script type=\"text/javascript\">");
			writer.Write("var ");
			writer.Write(variableNameOnClientSide + " = ");

			writer.Write(objectCreationString);
			writer.Write(";");
			writer.Write("</script>");
        }
    }
}
